/*
 *	LineChartWidget.cpp
 *
 * 	Copyright (C) 2011 Aaron Huang
 * 	This file is part of StackPainter.
 *
 * 	StackPainter is free software: you can redistribute it and/or modify
 * 	it under the terms of the GNU General Public License as published by
 * 	the Free Software Foundation, either version 3 of the License, or
 * 	(at your option) any later version.
 *
 * 	StackPainter is distributed in the hope that it will be useful,
 * 	but WITHOUT ANY WARRANTY; without even the implied warranty of
 * 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * 	GNU General Public License for more details.
 *
 * 	You should have received a copy of the GNU General Public License
 * 	along with StackPainter.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "LineChartWidget.h"

#include <QPainter>
#include <QPointF>
#include <QVector>


/*
 * 			border
 *  		graphic
 *  border	text area border
 *  		border
 */

const int BORDER = 50;		// The empty space at border.
const int TEXT_AREA = 70;	// The area for draw text.
const int GAP = 30;			// The gap between text and point.
const double DOT_SIZE = 5;	// The point size.

template <typename T>
LineChartWidget<T>::LineChartWidget(QWidget* parent) : QWidget(parent), _data(0) {}

template <typename T>
LineChartWidget<T>::~LineChartWidget() {}

template <typename T>
void LineChartWidget<T>::setData(const QMap<int, T>* data) {
	_data = data;
}

template <typename T>
void LineChartWidget<T>::paintEvent(QPaintEvent *) {
	if (_data != 0) {
		double minValue, maxValue;
		findBound(_data->values(), minValue, maxValue);
		// Compute the x distance of every value.
		const double xOffset = static_cast<double>(width() - 2 * BORDER) / (_data->size() - 1);
		double currentX = BORDER;
		int heightRange = height() - 2 * BORDER - TEXT_AREA;
		QPainter painter(this);
		painter.setRenderHint(QPainter::Antialiasing);
		// Move y coordinate to negative for showing.
		painter.translate(0, height());
		QVector<QPointF> points;
		for (QMap<int, double>::const_iterator it = _data->begin(); it != _data->end(); ++it) {
			double y = -(BORDER + TEXT_AREA + (((it.value() - minValue) / (maxValue - minValue)) *
					heightRange));
			(it.value() <= 0) ? painter.setPen(Qt::red) : painter.setPen(Qt::darkCyan);
			painter.drawEllipse(currentX- DOT_SIZE / 2, y - DOT_SIZE / 2, DOT_SIZE, DOT_SIZE);
			points.push_back(QPointF(currentX, y));
			painter.setPen(Qt::darkBlue);
			painter.drawText(currentX, y + GAP, QString::number(it.key()));
			painter.drawText(currentX, y + 2 * GAP, QString::number(it.value()));
			currentX += xOffset;
		}
		painter.setPen(Qt::darkCyan);
		painter.drawPolyline(points.begin(), points.size());
	}
}

template <typename T>
void LineChartWidget<T>::findBound(const QList<T> values, double& min, double& max) {
	min = max = values.first();
	foreach (T value, values) {
		if (value > max) {
			max = value;
		}
		if (value < min) {
			min = value;
		}
	}
}
